///////////////////////////////////////////////////////////////////////////////
//
// Licensed under the MIT License
//
// Copyright (c) 2010 Chris Colinsky
// All Rights Reserved
//
// version	0.5
// http://code.google.com/p/sugarcookie/
// http://code.google.com/p/sugarcookie/wiki/License
//
////////////////////////////////////////////////////////////////////////////////

package sugarcookie.utils {
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import mx.binding.utils.ChangeWatcher;
	import mx.collections.ArrayCollection;
	import mx.collections.CursorBookmark;
	import mx.collections.IViewCursor;
	import mx.events.PropertyChangeEvent;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.utils.ObjectUtil;
	
	import sugarcookie.error.ApplicationError;
	import sugarcookie.events.CollectionPropertyChangeEvent; 
	import sugarcookie.collections.EnhancedArrayCollection;
	
	public class CollectionWatcher extends EventDispatcher {
		private var _log:ILogger;
		private var _hosts:ArrayCollection;
		private var _watchers:ArrayCollection;
		private var _hostsCursor:IViewCursor;
		private var _listeners:EnhancedArrayCollection;
		private var _results:EnhancedArrayCollection;
		
		public function CollectionWatcher() {
			super();
			
			_log = Log.getLogger("sugarcookie.utils.CollectionWatcher");
			_hosts = new ArrayCollection();
			_listeners = new EnhancedArrayCollection();
			_results = new EnhancedArrayCollection();
			_watchers = new ArrayCollection();
		}
		
		public function addHost(host:Object):void {
			if (_hosts.contains(host)) {
				throw new ApplicationError("Host object already exists within collection.");
				return;
			}
			
			_hosts.addItem(host);
			if (_hosts.length==1) _hostsCursor = _hosts.createCursor();
		}
		
		public function addPropertyChangeListener(prop:String,listener:Function,value:Object=null):void {
			while (!_hostsCursor.afterLast) {
				var host:Object = _hostsCursor.current;
				_watchers.addItem( ChangeWatcher.watch(host,prop,propertyChange) );
				_hostsCursor.moveNext();
			}
			
			if (_listeners.containsKey(prop)) {
				var arr:Array = _listeners.getItemAtKey(prop) as Array;
				arr.push(listener);
			} else {
				_listeners.addItemWithKey(prop,[listener]);
			}
			
			if (!_results.containsKey(prop)) _results.addItemWithKey(prop,{targetValue:value,results:new EnhancedArrayCollection()});
		}
		
		public function destroy():void {
			for (var i:int=0;i<_watchers.length;i++) _watchers[i].unwatch();
			_watchers.removeAll();
			_hosts.removeAll();
			_listeners.removeAll();
			_results.removeAll();
		}
		
		private function propertyChange(evt:PropertyChangeEvent):void {
			var propResults:Object = _results.getItemAtKey(String(evt.property));
			propResults.results.addItemWithKey(evt.source.name, evt.newValue);
			
			processResults(String(evt.property));
		}
		
		private function processResults(prop:String):void {
			var status:Boolean = true;
			var propResults:Object = _results.getItemAtKey(prop);
			_hostsCursor.seek(CursorBookmark.FIRST);
			while (!_hostsCursor.afterLast) {
				if (!propResults.results.containsKey(_hostsCursor.current.name)) {
					if (propResults.results.getItemAtKey(_hostsCursor.current.name) != propResults.targetValue) status = false;
				}
				_hostsCursor.moveNext();
			}
			if (status) dispatchToListeners(prop,propResults.targetValue);
		}
		
		private function dispatchToListeners(prop:String,newValue:Object):void {
			var arr:Array = _listeners.getItemAtKey(prop) as Array;
			for (var c:int=0;c<arr.length;c++) {
				arr[0](new CollectionPropertyChangeEvent(CollectionPropertyChangeEvent.CHANGE,prop,newValue));
			}
		}	
	}
}










